Java:物联网终端机如何生成唯一识别码

您所在的位置:网站首页 linux md5查看 Java:物联网终端机如何生成唯一识别码

Java:物联网终端机如何生成唯一识别码

2022-12-29 02:26| 来源: 网络整理| 查看: 265

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情

1.前言

  最直接的思路是用CPU的序列号和主板编号来做,但是当你使用:sudo dmidecode -s baseboard-serial-number来获取主板编号时,大部分情况下会给你返回:

To be filled by O.E.M. 复制代码

  这个提示是令人崩溃的,虽然它可以被服务器的代加工厂任意指定,可是加工厂就是不写。

2.首先获取CPU序列号

  所以目前就剩下CPU的序列号了,CPU的序列号的获取方式很简单。CPU序号也有重复概率,网上有同志反映查到过同一批次服务器可能CPU ID 重复。

  好的,下面我们给出两个主要操作系统下的获取方法。评论区的朋友们可以补充其它系统的,俺没有,就不献丑了。

2.1.Linux dmidecode -t processor | grep 'ID' 复制代码 2.2.Windows wmic cpu get ProcessorId 复制代码 3.MAC地址为什么没用?

  主要原因是用户在连接多种通讯网络时,会拥有各式各样的Mac地址,使用哪一个都不好。并且心怀不轨的人还可以通过软件进行修改,达到伪装。具体的导论有很多,这里贴一个:How to get a unique computer identifier in Java (like disk ID or motherboard ID)?,这里面就提到,一个答主可以拥有下面这么多MAC地址:

lo MS TCP Loopback interface eth1 Intel(R) 82579LM Gigabit Network Connection eth2 VirtualBox Host-Only Ethernet Adapter eth3 Sterownik serwera dostepu do sieci LAN Bluetooth 复制代码 4.BIOS UUID

  在关于硬件:在Windows和Linux上使用Python获取唯一的计算机ID一文中提到:在现代PC硬件上,通常在BIOS中存储有一个UUID-在Linux上,有一个命令行实用程序dmidecode可以读取此信息。

  是不是有点眼熟?dmidecode这哥们又出现了,咱们简单介绍一下:

dmidecode在 Linux 系统下获取有关硬件方面的信息。dmidecode 遵循 SMBIOS/DMI 标准,以一种可读的方式dump出机器的DMI(Desktop Management Interface)信息, 其输出的信息包括 BIOS、系统、主板、处理器、内存、缓存等等, 既可以得到当前的配置,也可以得到系统支持的最大配置,比如说支持的最大内存数等。

  好的,下面我们给出两个主要操作系统下的获取方法。评论区的朋友们可以补充其它系统的,俺没有,就不献丑了。

4.1.Linux dmidecode -t system|grep UUID 复制代码 4.2.Windows wmic path win32_computersystemproduct get uuid 复制代码 5.如何缩短编码长度?

  现在CPU ID和BIOS UUID拼接在一起,已经52位长了,如果我们需要把它变成一个类似于1分钱优惠券激活码的东西让用户手动输入就太长了。

  这个时候,我们需要进行摘要,摘要算法有哪些呢?有MD5(Message Digest)、SHA(Secure Hash Algorithm)、HMAC(Hash-based Message Authentication Code)。记住一个简易技术选型方法——先试试MD5行不行,不行再说。

6.Java代码 6.1.MachineCodeUtil.java public class MachineCodeUtil { public static final String LINUX_OS_NAME = "LINUX"; public static final String SYSTEM_PROPERTY_OS_NAME = "os.name"; public static void main(String[] args) { System.out.println(getThisMachineCode()); System.out.println(getThisMachineCodeMd5()); } /** * 获取机器唯一识别码(CPU ID + BIOS UUID) * * @return 机器唯一识别码 */ public static String getThisMachineCode() { try { return getCpuId() + getBiosUuid(); } catch (Exception e) { e.printStackTrace(); } return ""; } /** * 获取机器码进行MD5摘要后的字符串 * * @return */ public static String getThisMachineCodeMd5() { try { String thisMachineCode = getThisMachineCode(); String md5Upper = MD5Utils.MD5Upper(thisMachineCode); return md5Upper; } catch (Exception e) { e.printStackTrace(); } return ""; } /** * 获取当前系统CPU序列,可区分linux系统和windows系统 */ public static String getCpuId() throws IOException { String cpuId; // 获取当前操作系统名称 String os = System.getProperty(SYSTEM_PROPERTY_OS_NAME); os = os.toUpperCase(); if (LINUX_OS_NAME.equals(os)) { cpuId = getLinuxDmidecodeInfo("dmidecode -t processor | grep 'ID'", "ID", ":"); } else { cpuId = getWindowsCpuId(); } return cpuId.toUpperCase().replace(" ", ""); } /** * 获取linux系统 * dmidecode * 命令的信息 */ public static String getLinuxDmidecodeInfo(String cmd, String record, String symbol) throws IOException { String execResult = executeLinuxCmd(cmd); String[] infos = execResult.split("\n"); for (String info : infos) { info = info.trim(); if (info.contains(record)) { info.replace(" ", ""); String[] sn = info.split(symbol); return sn[1]; } } return null; } /** * 执行Linux 命令 * * @param cmd Linux 命令 * @return 命令结果信息 * @throws IOException 执行命令期间发生的IO异常 */ public static String executeLinuxCmd(String cmd) throws IOException { Runtime run = Runtime.getRuntime(); Process process; process = run.exec(cmd); InputStream processInputStream = process.getInputStream(); StringBuilder stringBuilder = new StringBuilder(); byte[] b = new byte[8192]; for (int n; (n = processInputStream.read(b)) != -1; ) { stringBuilder.append(new String(b, 0, n)); } processInputStream.close(); process.destroy(); return stringBuilder.toString(); } /** * 获取windows系统CPU序列 */ public static String getWindowsCpuId() throws IOException { Process process = Runtime.getRuntime().exec( new String[]{"wmic", "cpu", "get", "ProcessorId"}); process.getOutputStream().close(); Scanner sc = new Scanner(process.getInputStream()); sc.next(); String serial = sc.next(); return serial; } /** * 获取 BIOS UUID * * @return BIOS UUID * @throws IOException 获取BIOS UUID期间的IO异常 */ public static String getBiosUuid() throws IOException { String cpuId; // 获取当前操作系统名称 String os = System.getProperty("os.name"); os = os.toUpperCase(); if ("LINUX".equals(os)) { cpuId = getLinuxDmidecodeInfo("dmidecode -t system | grep 'UUID'", "UUID", ":"); } else { cpuId = getWindowsBiosUUID(); } return cpuId.toUpperCase().replace(" ", ""); } /** * 获取windows系统 bios uuid * * @return * @throws IOException */ public static String getWindowsBiosUUID() throws IOException { Process process = Runtime.getRuntime().exec( new String[]{"wmic", "path", "win32_computersystemproduct", "get", "uuid"}); process.getOutputStream().close(); Scanner sc = new Scanner(process.getInputStream()); sc.next(); String serial = sc.next(); return serial; } } 复制代码 6.2.MD5Utils.java

  这一部分完全copy自Java MD5 加密工具类。

/** * MD5加密/验证工具类 * */ public class MD5Utils { static final char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; static final char hexDigitsLower[] = { '0', '1', '2', '3', '4', '5', '6', '7','8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** * 对字符串 MD5 无盐值加密 * * @param plainText * 传入要加密的字符串 * @return * MD5加密后生成32位(小写字母+数字)字符串 */ public static String MD5Lower(String plainText) { try { // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest md = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 md.update(plainText.getBytes()); // digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符 // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值 return new BigInteger(1, md.digest()).toString(16); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } /** * 对字符串 MD5 加密 * * @param plainText * 传入要加密的字符串 * @return * MD5加密后生成32位(大写字母+数字)字符串 */ public static String MD5Upper(String plainText) { try { // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest md = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 md.update(plainText.getBytes()); // 获得密文 byte[] mdResult = md.digest(); // 把密文转换成十六进制的字符串形式 int j = mdResult.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = mdResult[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf];// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移 str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换 } return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 对字符串 MD5 加盐值加密 * * @param plainText * 传入要加密的字符串 * @param saltValue * 传入要加的盐值 * @return * MD5加密后生成32位(小写字母+数字)字符串 */ public static String MD5Lower(String plainText, String saltValue) { try { // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest md = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 md.update(plainText.getBytes()); md.update(saltValue.getBytes()); // digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符 // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值 return new BigInteger(1, md.digest()).toString(16); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } /** * 对字符串 MD5 加盐值加密 * * @param plainText * 传入要加密的字符串 * @param saltValue * 传入要加的盐值 * @return * MD5加密后生成32位(大写字母+数字)字符串 */ public static String MD5Upper(String plainText, String saltValue) { try { // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest md = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 md.update(plainText.getBytes()); md.update(saltValue.getBytes()); // 获得密文 byte[] mdResult = md.digest(); // 把密文转换成十六进制的字符串形式 int j = mdResult.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = mdResult[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } /** * MD5加密后生成32位(小写字母+数字)字符串 * 同 MD5Lower() 一样 */ public final static String MD5(String plainText) { try { MessageDigest mdTemp = MessageDigest.getInstance("MD5"); mdTemp.update(plainText.getBytes("UTF-8")); byte[] md = mdTemp.digest(); int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigitsLower[byte0 >>> 4 & 0xf]; str[k++] = hexDigitsLower[byte0 & 0xf]; } return new String(str); } catch (Exception e) { return null; } } /** * 校验MD5码 * * @param text * 要校验的字符串 * @param md5 * md5值 * @return 校验结果 */ public static boolean valid(String text, String md5) { return md5.equals(MD5(text)) || md5.equals(MD5(text).toUpperCase()); } } 复制代码 7.最终效果

  最终,你会获得类似于下面这样的字符串:

B6C15A6BF77C90244115E8E7B623F34C 复制代码

  当然了,如果你喜欢,可以每四位添加一个横杠,就像下面这样:

B6C1-5A6B-F77C-9024-4115-E8E7-B623-F34C 复制代码

  是不是有那味儿了?感觉下一秒钟就要拿着优惠券购买玛莎拉蒂了?

8.结语

  另外,如果您能够保证用户不更换硬盘,硬盘的ID真的是不错的选择。

  当我们获取到当前设备的唯一识别码,我们可以做很多有价值的事情。其实最有价值的还是去重,若后期有更好的方法,我也会分享给大家。希望看完博文的你没有bug。

参考资料

排名不分先后:

How to Get the BIOS UUID dmidecode命令 使用Java实现信息摘要算法 主板型号:to be filled by O.E.M,这是什么情况? How to uniquely identify computer using C#?


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3